﻿using Furion.DataEncryption;
using Furion.JsonSerialization;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.International.Converters.PinYinConverter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Mrhd.Core.Extensions
{
    /// <summary>
    /// 公共的扩展方法类
    /// </summary>
    public static class CommonExtensions
    {
        /// <summary>
        /// 将对象序列化为字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJson<T>(this T obj) where T : class
        {
            var _jsonSerializer = JSON.GetJsonSerializer();     // 获取系统默认的JSON序列化器
            return _jsonSerializer.Serialize(obj);
        }

        /// <summary>
        /// 将字符串序列化为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="content"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string content) where T : class, new()
        {
            if (string.IsNullOrEmpty(content)) return default;
            var _jsonSerializer = JSON.GetJsonSerializer();     // 获取系统默认的JSON序列化器
            return _jsonSerializer.Deserialize<T>(content);
        }

        /// <summary>
        /// 读取分布式缓存中的内容，并且格式化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cache"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<T> ObjectGetAsync<T>(this IDistributedCache cache, string key)
        {
            var value = await cache.GetStringAsync(key);
            if (value == null) return default;
            var _jsonSerializer = JSON.GetJsonSerializer();
            return _jsonSerializer.Deserialize<T>(value);
        }

        /// <summary>
        /// 设置分布式缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cache"></param>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <param name="options"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public static async Task<bool> ObjectSetAsync<T>(this IDistributedCache cache, string key, T obj, DistributedCacheEntryOptions options = null, CancellationToken token = default) where T : class
        {
            if (obj == null)
            {
                throw new NullReferenceException("设置Redis对象引用为空");
            }
            var content = obj.ToJson();
            await cache.SetStringAsync(key, content, options ?? new(), token);
            return true;
        }

        /// <summary>
        /// 获取byte[]
        /// </summary>
        /// <param name="str"></param>
        /// <param name="encoding">字符编码</param>
        /// <returns></returns>
        public static byte[] ToBytes(this string str, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            return encoding.GetBytes(str);
        }

        /// <summary>
        /// 转化为整型
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int ToInt(this string str)
        {
            if (string.IsNullOrEmpty(str)) return 0;
            return Convert.ToInt32(str);
        }

        /// <summary>
        /// 将二进制数组转化为字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="encoding">字符编码</param>
        /// <returns></returns>
        public static string ToStr(this byte[] buffer, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            return encoding.GetString(buffer);
        }

        /// <summary>
        /// 遍历列表，执行函数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> predicate)
        {
            foreach (var item in list)
            {
                predicate(item);
            }
            return list;
        }

        /// <summary>
        /// 遍历列表，执行函数（异步）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static async Task<IEnumerable<T>> ForEachAsync<T>(this IEnumerable<T> list, Func<T, Task> predicate)
        {
            foreach (var item in list)
            {
                await predicate(item);
            }
            return list;
        }

        /// <summary>
        /// 将时间转化为时间戳（秒级）
        /// </summary>
        /// <param name="dateTime">时间</param>
        /// <returns></returns>
        public static long ToTimestamp(this DateTimeOffset dateTime)
        {
            return dateTime.ToUnixTimeSeconds();
        }

        /// <summary>
        /// 将时间戳转化为时间（秒级）
        /// </summary>
        /// <param name="timestamp">时间戳</param>
        /// <returns></returns>
        public static DateTimeOffset ToDateTime(this long timestamp)
        {
            return DateTimeOffset.FromUnixTimeSeconds(timestamp);
        }

        /// <summary>
        /// 将字符串转化为拼音
        /// </summary>
        /// <param name="str">汉字</param>
        /// <returns></returns>
        public static string ToPinyin(this string str)
        {
            if (string.IsNullOrEmpty(str)) return null;
            var list = new List<List<string>>();
            foreach (char obj in str)
            {
                var chars = new List<string>();
                list.Add(chars);
                if (!ChineseChar.IsValidChar(obj))
                {
                    chars.Add(obj.ToString());
                    continue;
                }
                var chineseChar = new ChineseChar(obj);
                foreach (var item in chineseChar.Pinyins.Where(a => a != null))
                {
                    var pinyin = item[0..^1];
                    if (chars.Contains(pinyin)) continue;
                    chars.Add(pinyin);
                }
            }

            return string.Join(",", CombineString(list[0], list.GetRange(1, list.Count - 1))).ToLower();
        }

        /// <summary>
        /// 汉字转化为拼音首字母
        /// </summary>
        /// <param name="str">汉字</param>
        /// <returns>首字母</returns>
        public static string ToFirstLatter(this string str)
        {
            if (string.IsNullOrEmpty(str)) return null;
            List<List<string>> list = new List<List<string>>();
            foreach (char obj in str)
            {
                var chars = new List<string>();
                list.Add(chars);
                if (!ChineseChar.IsValidChar(obj))
                {
                    chars.Add(obj.ToString());
                    continue;
                }
                var chineseChar = new ChineseChar(obj);
                foreach (var item in chineseChar.Pinyins.Where(a => a != null))
                {
                    var firstLetter = item.Substring(0, 1);
                    if (chars.Contains(firstLetter)) continue;
                    chars.Add(firstLetter);
                }
            }
            return string.Join(",", CombineString(list[0], list.GetRange(1, list.Count - 1))).ToLower();
        }

        /// <summary>
        /// 生成随机数字
        /// </summary>
        /// <param name="str"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string RandomNumber(this string str, int len = 6)
        {
            var arrChar = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
            var num = new StringBuilder();
            var rnd = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i < len; i++)
            {
                num.Append(arrChar[rnd.Next(0, 9)]);
            }
            return num.ToString();
        }

        /// <summary>
        /// AES-128-CBC
        /// </summary>
        /// <param name="input">加密字符串</param>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        /// <returns></returns>
        public static string AESDecrypt(this string input, string key, string iv)
        {
            var encryptedData = Convert.FromBase64String(input);
            var rijndaelCipher = new RijndaelManaged
            {
                Key = Convert.FromBase64String(key),
                IV = Convert.FromBase64String(iv),
                Mode = CipherMode.CBC,
                Padding = PaddingMode.PKCS7
            };
            var transform = rijndaelCipher.CreateDecryptor();
            var plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
            var result = Encoding.UTF8.GetString(plainText);
            return result;
        }



        #region 私有
        /// <summary>
        /// 递归字符串列表，按笛卡尔积排列
        /// </summary>
        /// <param name="resultList"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        private static List<string> CombineString(List<string> resultList, List<List<string>> list)
        {
            if (list == null || list.Count == 0) return resultList;
            var result = new List<string>();
            foreach (var item in list[0])
            {
                foreach (var str in resultList)
                {
                    result.Add(str + item);
                }
            }
            var combineArr = list.GetRange(1, list.Count - 1);
            return CombineString(result, combineArr);
        }
        #endregion
    }
}
